package com.accedo.achievements.dataaccess.dao.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.accedo.achievements.dataaccess.dao.AchievementDao;
import com.accedo.achievements.dataaccess.model.Achievement;
import com.accedo.achievements.dataaccess.model.Badge;
import com.accedo.achievements.dataaccess.model.Campaign;
//import com.accedo.achievements.dataaccess.util.SessionFactoryUtil;

/**
 * A DAO class with achievement model database operations.
 * @author Bo Liang
 */
@Component
public class AchievementDaoImpl implements AchievementDao {

	private static final Logger log = LoggerFactory.getLogger(AchievementDaoImpl.class);
	
	private SessionFactory sessionFactory; //injection
	private Achievement achi; //injection
	private Badge badge; //injection
	private Campaign camp; //injection

	// Constructor
	AchievementDaoImpl() {};
	
	/**
	 * Get achievement object by achievement sn.
	 * <p>obtain the achievement object instance by using this achievement serial number<br>
	 * @param	achi_sn	achievement serial number
	 * @return 			achievement object
	 */
	public Achievement getAchiByAchisn(String achi_sn) {
		log.debug("Entering getAchiByAchisn(achi_sn = {})", achi_sn);
		Session session = null; 
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession();
			Query query = session.createQuery("from Achievement achi where achi.achi_sn = :achi_sn")
						  .setParameter("achi_sn", achi_sn); 
			achi = (Achievement)query.uniqueResult();  
		} catch (Exception e) {
			e.printStackTrace();
			log.error("getAchiByAchisn Catch Exception: {}", e.getMessage());
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}
		log.debug("Entering getAchiByAchisn() : achi_name = {}", achi.getAchi_name());
		return achi; 
	}
	
	
	/**
	 * Get all achievements which belong to the specific application
	 * <p>By using application's serial number, fetch all this application's achievements into List<br>
	 * @param	app_sn	application serial number
	 * @return			achievements List
	 */
	@SuppressWarnings("unchecked")
	public List<Achievement> getAchiListByAppsn(String app_sn) {
		log.debug("Entering getAchiListByAppsn(app_sn = {})", app_sn);
		List<Achievement> achiList = new ArrayList<Achievement>();
		Session session = null; 
		try {
			session = sessionFactory.openSession();
			Query query = session.createQuery("from Achievement achi where achi.app_sn = :app_sn order by achi.achi_sn desc")
					      .setParameter("app_sn", app_sn); 
			achiList = query.list();  
		} catch (Exception e) {
			e.printStackTrace();
			log.error("getAchiListByAppsn Catch Exception: {}", e.getMessage());
		} finally {
			session.close();
		}
		log.debug("Entering getAchiListByAppsn() : achiList.size = {}", achiList.size());
		return achiList; 
	}
	
	/**
	 * Get one specific badge's all achievements by using this badge's serial number.
	 * @param badge_sn	badge serial number
	 * @return			Set of achievement object
	 */
	public Set<Achievement> getAchiListByBadgesn(String badge_sn) {
		log.debug("Entering getAchiListByBadgesn(badge_sn = {})", badge_sn);
		Set<Achievement> achiSet = new HashSet<Achievement>(); 
		Session session = null; 
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession();
			Query query = session.createQuery("from Badge badge where badge.badge_sn = :badge_sn")
					.setParameter("badge_sn", badge_sn); 
			badge = (Badge)query.uniqueResult(); 
			achiSet = badge.getAchis(); 
			
		} catch (Exception e) {
			e.printStackTrace();
			log.error("getAchiListByBadgesn Catch Exception: {}", e.getMessage());
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}
		log.debug("Entering getAchiListByBadgesn() : achiSet.size = {}", achiSet.size());
		return achiSet; 
	}
	
	/**
	 * Get all achievements which refer to the specific campaign.
	 * @param camp_sn	campaign serial number
	 * @return			Set of achievement object
	 */
	public Set<Achievement> getAchiListByCampsn(String camp_sn) {
		log.debug("Entering getAchiListByCampsn(camp_sn = {})", camp_sn);
		Set<Achievement> achiSet = new HashSet<Achievement>(); 
		Session session = null; 
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession();
			Query query = session.createQuery("from Campaign camp where camp.camp_sn = :camp_sn")
					.setParameter("camp_sn", camp_sn); 
			camp = (Campaign)query.uniqueResult(); 
			achiSet = camp.getAchis(); 
		
		} catch (Exception e) {
			e.printStackTrace();
			log.error("getAchiListByCampsn Catch Exception: {}", e.getMessage());
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}
		log.debug("Entering getAchiListByCampsn() : achiSet.size = {}", achiSet.size());
		return achiSet; 
	}
	
	/**
	 * Get the application's achievements quantity by using application sn.
	 * <p>this function will go to search and count the achievements quantity from achievement table.
	 * @param app_sn	application serial number
	 * @return			application's achievements quantity
	 */
	public int getAchiQuantityByAppsn(String app_sn) {
		log.debug("Entering getAchiQuantityByAppsn(app_sn = {})", app_sn);
		
		int achiQuantity = 0; 
		Session session = null; 
		try {
			session = sessionFactory.openSession();
			Query query = session.createSQLQuery("select count(app_sn) from t_achievement where app_sn = :app_sn")
					      .setParameter("app_sn", app_sn); 
			achiQuantity = ((Number)query.uniqueResult()).intValue(); 
		} catch (Exception e) {
			e.printStackTrace();
			log.error("getAchiQuantityByAppsn Catch Exception: {}", e.getMessage());
		} finally {
			session.close();
		}
		
		log.debug("Leaving getAchiQuantityByAppsn() : achiQuantity = {})", achiQuantity);
		return achiQuantity;
	}
	
	/**
	 * Get the application's achievements quantity by using user id and applicaiton sn.
	 * <p>this function will go to search and count the achievements quantity from one user's one application.
	 * @param user_id	user id
	 * @param app_sn	application serial number
	 * @return			achievement quantity
	 */
	public int getAchiQuantityByUserIdAndAppsn(int user_id, String app_sn) {
		log.debug("Entering getAchiQuantityByUserIdAndAppsn(user_id = {}, app_sn = {})", user_id, app_sn);
		
		int achiQuantity = 0;; 
		Session session = null; 
		try {
			session = sessionFactory.openSession();
			Query query = session.createSQLQuery("select count(app_sn) from t_user_achievement where user_id = :user_id and app_sn = :app_sn")
					      .setParameter("user_id", user_id)
					      .setParameter("app_sn", app_sn);
			achiQuantity = ((Number)query.uniqueResult()).intValue(); 
		} catch (Exception e) {
			e.printStackTrace();
			log.error("getAchiQuantityByUserIdAndAppsn Catch Exception: {}", e.getMessage());
		} finally {
			session.close();
		}
		
		log.debug("Entering getAchiQuantityByUserIdAndAppsn() : achiQuantity = {}", achiQuantity);
		return achiQuantity;
	}
	
	
	public Achievement getAchi() {
		return achi;
	}

	@Resource
	public void setAchi(Achievement achi) {
		this.achi = achi;
	}
	
	public Badge getBadge() {
		return badge;
	}

	@Resource
	public void setBadge(Badge badge) {
		this.badge = badge;
	}
	
	public Campaign getCamp() {
		return camp;
	}

	@Resource
	public void setCamp(Campaign camp) {
		this.camp = camp;
	}


	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	@Resource
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
}
